home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / libsrc / c / io / doprnt.c1 < prev    next >
Encoding:
Text File  |  1994-07-18  |  18.3 KB  |  758 lines

  1. /* This is file DOPRNT.C */
  2. /* This file may have been modified by DJ Delorie (Jan 1991).  If so,
  3. ** these modifications are Coyright (C) 1993 DJ Delorie, 24 Kirsten Ave,
  4. ** Rochester NH, 03867-2954, USA.
  5. */
  6.  
  7. /*
  8.  * Copyright (c) 1988 Regents of the University of California.
  9.  * All rights reserved.
  10.  *
  11.  * Redistribution and use in source and binary forms are permitted provided
  12.  * that: (1) source distributions retain this entire copyright notice and
  13.  * comment, and (2) distributions including binaries display the following
  14.  * acknowledgement:  ``This product includes software developed by the
  15.  * University of California, Berkeley and its contributors'' in the
  16.  * documentation or other materials provided with the distribution and in
  17.  * all advertising materials mentioning features or use of this software.
  18.  * Neither the name of the University nor the names of its contributors may
  19.  * be used to endorse or promote products derived from this software without
  20.  * specific prior written permission.
  21.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  22.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  23.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  24.  */
  25.  
  26. #if defined(LIBC_SCCS) && !defined(lint)
  27. static char sccsid[] = "@(#)doprnt.c    5.39 (Berkeley) 6/28/90";
  28. #endif /* LIBC_SCCS and not lint */
  29.  
  30. #define _doprnt ____doprnt
  31. #include <sys/types.h>
  32. #include <varargs.h>
  33. #include <stdio.h>
  34. #include <ctype.h>
  35. #include <locale.h>
  36. #undef _doprnt
  37.  
  38. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  39. #define    MAXEXP        308
  40. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  41. #define    MAXFRACT    39
  42.  
  43. #define    DEFPREC        6
  44. #define    DEFLPREC    14
  45.  
  46. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  47.  
  48. #define    PUTC(ch)    (void) putc(ch, fp)
  49.  
  50. #define ARG(basetype) \
  51.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  52.         flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
  53.         va_arg(argp, int)
  54.  
  55. static int nan = 0;
  56.  
  57. static char decimal;
  58.  
  59. #if 0
  60. #define    todigit(c)    ((c) - '0')
  61. #define    tochar(n)    ((n) + '0')
  62. #else
  63. static int todigit(char c)
  64. {
  65.   if (c<='0') return 0;
  66.   if (c>='9') return 9;
  67.   return c-'0';
  68. }
  69. static char tochar(int n)
  70. {
  71.   if (n>=9) return '9';
  72.   if (n<=0) return '0';
  73.   return n+'0';
  74. }
  75. #endif
  76.  
  77. /* have to deal with the negative buffer count kludge */
  78. #define    NEGATIVE_COUNT_KLUDGE
  79.  
  80. #define    LONGINT        0x01        /* long integer */
  81. #define    LONGDBL        0x02        /* long double; unimplemented */
  82. #define    SHORTINT    0x04        /* short integer */
  83. #define    ALT        0x08        /* alternate form */
  84. #define    LADJUST        0x10        /* left adjustment */
  85. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  86. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  87.  
  88. _doprnt(fmt0, argp, fp)
  89.     const char *fmt0;
  90.     va_list argp;
  91.     FILE *fp;
  92. {
  93.     u_char *fmt;        /* format string */
  94.     int ch;            /* character from fmt */
  95.     int cnt;        /* return value accumulator */
  96.     int n;            /* random handy integer */
  97.     char *t;        /* buffer pointer */
  98.     double _double;        /* double precision arguments %[eEfgG] */
  99.     u_long _ulong;        /* integer arguments %[diouxX] */
  100.     int base;        /* base for [diouxX] conversion */
  101.     int dprec;        /* decimal precision in [diouxX] */
  102.     int fieldsz;        /* field size expanded by sign, etc */
  103.     int flags;        /* flags as above */
  104.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  105.     int prec;        /* precision from format (%.3d), or -1 */
  106.     int realsz;        /* field size expanded by decimal precision */
  107.     int size;        /* size of converted field or string */
  108.     int width;        /* width from format (%8d), or 0 */
  109.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  110.     char softsign;        /* temporary negative sign for floats */
  111.     char *digs;        /* digits for [diouxX] conversion */
  112.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  113.  
  114.     decimal = localeconv()->decimal_point[0];
  115.  
  116.     if (fp->_flag & _IORW) {
  117.         fp->_flag |= _IOWRT;
  118.         fp->_flag &= ~(_IOEOF|_IOREAD);
  119.     }
  120.     if ((fp->_flag & _IOWRT) == 0)
  121.         return (EOF);
  122.  
  123.     fmt = fmt0;
  124.     digs = "0123456789abcdef";
  125.     for (cnt = 0;; ++fmt) {
  126.         n = fp->_cnt;
  127.         for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
  128.              ++cnt, ++fmt)
  129.             if (--n < 0
  130. #ifdef NEGATIVE_COUNT_KLUDGE
  131.                 && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
  132. #endif
  133.                 || ch == '\n' && fp->_flag & _IOLBF) {
  134.                 fp->_cnt = n;
  135.                 fp->_ptr = t;
  136.                 (void) _flsbuf((u_char)ch, fp);
  137.                 n = fp->_cnt;
  138.                 t = (char *)fp->_ptr;
  139.             } else
  140.                 *t++ = ch;
  141.         fp->_cnt = n;
  142.         fp->_ptr = t;
  143.         if (!ch)
  144.             return (cnt);
  145.  
  146.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  147.         prec = -1;
  148.         sign = '\0';
  149.  
  150. rflag:        switch (*++fmt) {
  151.         case ' ':
  152.             /*
  153.              * ``If the space and + flags both appear, the space
  154.              * flag will be ignored.''
  155.              *    -- ANSI X3J11
  156.              */
  157.             if (!sign)
  158.                 sign = ' ';
  159.             goto rflag;
  160.         case '#':
  161.             flags |= ALT;
  162.             goto rflag;
  163.         case '*':
  164.             /*
  165.              * ``A negative field width argument is taken as a
  166.              * - flag followed by a  positive field width.''
  167.              *    -- ANSI X3J11
  168.              * They don't exclude field widths read from args.
  169.              */
  170.             if ((width = va_arg(argp, int)) >= 0)
  171.                 goto rflag;
  172.             width = -width;
  173.             /* FALLTHROUGH */
  174.         case '-':
  175.             flags |= LADJUST;
  176.             goto rflag;
  177.         case '+':
  178.             sign = '+';
  179.             goto rflag;
  180.         case '.':
  181.             if (*++fmt == '*')
  182.                 n = va_arg(argp, int);
  183.             else {
  184.                 n = 0;
  185.                 while (isascii(*fmt) && isdigit(*fmt))
  186.                     n = 10 * n + todigit(*fmt++);
  187.                 --fmt;
  188.             }
  189.             prec = n < 0 ? -1 : n;
  190.             goto rflag;
  191.         case '0':
  192.             /*
  193.              * ``Note that 0 is taken as a flag, not as the
  194.              * beginning of a field width.''
  195.              *    -- ANSI X3J11
  196.              */
  197.             flags |= ZEROPAD;
  198.             goto rflag;
  199.         case '1': case '2': case '3': case '4':
  200.         case '5': case '6': case '7': case '8': case '9':
  201.             n = 0;
  202.             do {
  203.                 n = 10 * n + todigit(*fmt);
  204.             } while (isascii(*++fmt) && isdigit(*fmt));
  205.             width = n;
  206.             --fmt;
  207.             goto rflag;
  208.         case 'L':
  209.             flags |= LONGDBL;
  210.             goto rflag;
  211.         case 'h':
  212.             flags |= SHORTINT;
  213.             goto rflag;
  214.         case 'l':
  215.             flags |= LONGINT;
  216.             goto rflag;
  217.         case 'c':
  218.             *(t = buf) = va_arg(argp, int);
  219.             size = 1;
  220.             sign = '\0';
  221.             goto pforw;
  222.         case 'D':
  223.             flags |= LONGINT;
  224.             /*FALLTHROUGH*/
  225.         case 'd':
  226.         case 'i':
  227.             ARG(int);
  228.             if ((long)_ulong < 0) {
  229.                 _ulong = -_ulong;
  230.                 sign = '-';
  231.             }
  232.             base = 10;
  233.             goto number;
  234.         case 'e':
  235.         case 'E':
  236.         case 'f':
  237.         case 'g':
  238.         case 'G':
  239.             _double = va_arg(argp, double);
  240.             /*
  241.              * don't do unrealistic precision; just pad it with
  242.              * zeroes later, so buffer size stays rational.
  243.              */
  244.             if (prec > MAXFRACT) {
  245.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  246.                     fpprec = prec - MAXFRACT;
  247.                 prec = MAXFRACT;
  248.             }
  249.             else if (prec == -1)
  250.             {
  251.                 if (flags&LONGINT)
  252.                     prec = DEFLPREC;
  253.                 else
  254.                     prec = DEFPREC;
  255.             }
  256.             /*
  257.              * softsign avoids negative 0 if _double is < 0 and
  258.              * no significant digits will be shown
  259.              */
  260.             if (_double < 0) {
  261.                 softsign = '-';
  262.                 _double = -_double;
  263.             }
  264.             else
  265.                 softsign = 0;
  266.             /*
  267.              * cvt may have to round up past the "start" of the
  268.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  269.              * if the first char isn't NULL, it did.
  270.              */
  271.             *buf = NULL;
  272.             size = cvt(_double, prec, flags, &softsign, *fmt, buf,
  273.                 buf + sizeof(buf));
  274.             if (softsign && !nan)
  275.                 sign = '-';
  276.             nan = 0;
  277.             t = *buf ? buf : buf + 1;
  278.             goto pforw;
  279.         case 'n':
  280.             if (flags & LONGINT)
  281.                 *va_arg(argp, long *) = cnt;
  282.             else if (flags & SHORTINT)
  283.                 *va_arg(argp, short *) = cnt;
  284.             else
  285.                 *va_arg(argp, int *) = cnt;
  286.             break;
  287.         case 'O':
  288.             flags |= LONGINT;
  289.             /*FALLTHROUGH*/
  290.         case 'o':
  291.             ARG(unsigned);
  292.             base = 8;
  293.             goto nosign;
  294.         case 'p':
  295.             /*
  296.              * ``The argument shall be a pointer to void.  The
  297.              * value of the pointer is converted to a sequence
  298.              * of printable characters, in an implementation-
  299.              * defined manner.''
  300.              *    -- ANSI X3J11
  301.              */
  302.             /* NOSTRICT */
  303.             _ulong = (u_long)va_arg(argp, void *);
  304.             base = 16;
  305.             goto nosign;
  306.         case 's':
  307.             if (!(t = va_arg(argp, char *)))
  308.                 t = "(null)";
  309.             if (prec >= 0) {
  310.                 /*
  311.                  * can't use strlen; can only look for the
  312.                  * NUL in the first `prec' characters, and
  313.                  * strlen() will go further.
  314.                  */
  315.                 char *p, *memchr();
  316.  
  317.                 if (p = memchr(t, 0, prec)) {
  318.                     size = p - t;
  319.                     if (size > prec)
  320.                         size = prec;
  321.                 } else
  322.                     size = prec;
  323.             } else
  324.                 size = strlen(t);
  325.             sign = '\0';
  326.             goto pforw;
  327.         case 'U':
  328.             flags |= LONGINT;
  329.             /*FALLTHROUGH*/
  330.         case 'u':
  331.             ARG(unsigned);
  332.             base = 10;
  333.             goto nosign;
  334.         case 'X':
  335.             digs = "0123456789ABCDEF";
  336.             /* FALLTHROUGH */
  337.         case 'x':
  338.             ARG(unsigned);
  339.             base = 16;
  340.             /* leading 0x/X only if non-zero */
  341.             if (flags & ALT && _ulong != 0)
  342.                 flags |= HEXPREFIX;
  343.  
  344.             /* unsigned conversions */
  345. nosign:            sign = '\0';
  346.             /*
  347.              * ``... diouXx conversions ... if a precision is
  348.              * specified, the 0 flag will be ignored.''
  349.              *    -- ANSI X3J11
  350.              */
  351. number:            if ((dprec = prec) >= 0)
  352.                 flags &= ~ZEROPAD;
  353.  
  354.             /*
  355.              * ``The result of converting a zero value with an
  356.              * explicit precision of zero is no characters.''
  357.              *    -- ANSI X3J11
  358.              */
  359.             t = buf + BUF;
  360.             if (_ulong != 0 || prec != 0) {
  361.                 do {
  362.                     *--t = digs[_ulong % base];
  363.                     _ulong /= base;
  364.                 } while (_ulong);
  365.                 digs = "0123456789abcdef";
  366.                 if (flags & ALT && base == 8 && *t != '0')
  367.                     *--t = '0'; /* octal leading 0 */
  368.             }
  369.             size = buf + BUF - t;
  370.  
  371. pforw:
  372.             /*
  373.              * All reasonable formats wind up here.  At this point,
  374.              * `t' points to a string which (if not flags&LADJUST)
  375.              * should be padded out to `width' places.  If
  376.              * flags&ZEROPAD, it should first be prefixed by any
  377.              * sign or other prefix; otherwise, it should be blank
  378.              * padded before the prefix is emitted.  After any
  379.              * left-hand padding and prefixing, emit zeroes
  380.              * required by a decimal [diouxX] precision, then print
  381.              * the string proper, then emit zeroes required by any
  382.              * leftover floating precision; finally, if LADJUST,
  383.              * pad with blanks.
  384.              */
  385.  
  386.             /*
  387.              * compute actual size, so we know how much to pad
  388.              * fieldsz excludes decimal prec; realsz includes it
  389.              */
  390.             fieldsz = size + fpprec;
  391.             realsz = dprec > fieldsz ? dprec : fieldsz;
  392.             if (sign)
  393.                 realsz++;
  394.             if (flags & HEXPREFIX)
  395.                 realsz += 2;
  396.  
  397.             /* right-adjusting blank padding */
  398.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  399.                 for (n = realsz; n < width; n++)
  400.                     PUTC(' ');
  401.             /* prefix */
  402.             if (sign)
  403.                 PUTC(sign);
  404.             if (flags & HEXPREFIX) {
  405.                 PUTC('0');
  406.                 PUTC((char)*fmt);
  407.             }
  408.             /* right-adjusting zero padding */
  409.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  410.                 for (n = realsz; n < width; n++)
  411.                     PUTC('0');
  412.             /* leading zeroes from decimal precision */
  413.             for (n = fieldsz; n < dprec; n++)
  414.                 PUTC('0');
  415.  
  416.             /* the string or number proper */
  417.             n = size;
  418.             if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0) {
  419.                 fp->_cnt -= n;
  420.                 bcopy(t, (char *)fp->_ptr, n);
  421.                 fp->_ptr += n;
  422.             } else
  423.                 while (--n >= 0)
  424.                     PUTC(*t++);
  425.             /* trailing f.p. zeroes */
  426.             while (--fpprec >= 0)
  427.                 PUTC('0');
  428.             /* left-adjusting padding (always blank) */
  429.             if (flags & LADJUST)
  430.                 for (n = realsz; n < width; n++)
  431.                     PUTC(' ');
  432.             /* finally, adjust cnt */
  433.             cnt += width > realsz ? width : realsz;
  434.             break;
  435.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  436.             return (cnt);
  437.         default:
  438.             PUTC((char)*fmt);
  439.             cnt++;
  440.         }
  441.     }
  442.     /* NOTREACHED */
  443. }
  444.  
  445. static
  446. cvt(number, prec, flags, signp, fmtch, startp, endp)
  447.     double number;
  448.     register int prec;
  449.     int flags;
  450.     u_char fmtch;
  451.     char *signp, *startp, *endp;
  452. {
  453.     register char *p, *t;
  454.     register double fract;
  455.     int dotrim, expcnt, gformat;
  456.     double integer, tmp, modf();
  457.     char *exponent(), *round();
  458.  
  459. #ifdef hp300
  460.     if (expcnt = isspecial(number, startp, signp))
  461.         return(expcnt);
  462. #endif
  463. #ifdef __GO32__
  464.     if (expcnt = isspecial(number, startp))
  465.         return(expcnt);
  466. #endif
  467.  
  468.     dotrim = expcnt = gformat = 0;
  469.     fract = modf(number, &integer);
  470.  
  471.     /* get an extra slot for rounding. */
  472.     t = ++startp;
  473.  
  474.     /*
  475.      * get integer portion of number; put into the end of the buffer; the
  476.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  477.      */
  478.     for (p = endp - 1; integer; ++expcnt) {
  479.         tmp = modf(integer / 10, &integer);
  480.         *p-- = tochar((int)((tmp + .01) * 10));
  481.     }
  482.     switch(fmtch) {
  483.     case 'f':
  484.         /* reverse integer into beginning of buffer */
  485.         if (expcnt)
  486.             for (; ++p < endp; *t++ = *p);
  487.         else
  488.             *t++ = '0';
  489.         /*
  490.          * if precision required or alternate flag set, add in a
  491.          * decimal point.
  492.          */
  493.         if (prec || flags&ALT)
  494.             *t++ = decimal;
  495.         /* if requires more precision and some fraction left */
  496.         if (fract) {
  497.             if (prec)
  498.                 do {
  499.                     fract = modf(fract * 10, &tmp);
  500.                     *t++ = tochar((int)tmp);
  501.                 } while (--prec && fract);
  502.             if (fract)
  503.                 startp = round(fract, (int *)NULL, startp,
  504.                     t - 1, (char)0, signp);
  505.         }
  506.         for (; prec--; *t++ = '0');
  507.         break;
  508.     case 'e':
  509.     case 'E':
  510. eformat:    if (expcnt) {
  511.             *t++ = *++p;
  512.             if (prec || flags&ALT)
  513.                 *t++ = decimal;
  514.             /* if requires more precision and some integer left */
  515.             for (; prec && ++p < endp; --prec)
  516.                 *t++ = *p;
  517.             /*
  518.              * if done precision and more of the integer component,
  519.              * round using it; adjust fract so we don't re-round
  520.              * later.
  521.              */
  522.             if (!prec && ++p < endp) {
  523.                 fract = 0;
  524.                 startp = round((double)0, &expcnt, startp,
  525.                     t - 1, *p, signp);
  526.             }
  527.             /* adjust expcnt for digit in front of decimal */
  528.             --expcnt;
  529.         }
  530.         /* until first fractional digit, decrement exponent */
  531.         else if (fract) {
  532.             /* adjust expcnt for digit in front of decimal */
  533.             for (expcnt = -1;; --expcnt) {
  534.                 fract = modf(fract * 10, &tmp);
  535.                 if (tmp)
  536.                     break;
  537.             }
  538.             *t++ = tochar((int)tmp);
  539.             if (prec || flags&ALT)
  540.                 *t++ = decimal;
  541.         }
  542.         else {
  543.             *t++ = '0';
  544.             if (prec || flags&ALT)
  545.                 *t++ = decimal;
  546.         }
  547.         /* if requires more precision and some fraction left */
  548.         if (fract) {
  549.             if (prec)
  550.                 do {
  551.                     fract = modf(fract * 10, &tmp);
  552.                     *t++ = tochar((int)tmp);
  553.                 } while (--prec && fract);
  554.             if (fract)
  555.                 startp = round(fract, &expcnt, startp,
  556.                     t - 1, (char)0, signp);
  557.         }
  558.         /* if requires more precision */
  559.         for (; prec--; *t++ = '0');
  560.  
  561.         /* unless alternate flag, trim any g/G format trailing 0's */
  562.         if (gformat && !(flags&ALT)) {
  563.             while (t > startp && *--t == '0');
  564.             if (*t == decimal)
  565.                 --t;
  566.             ++t;
  567.         }
  568.         t = exponent(t, expcnt, fmtch);
  569.         break;
  570.     case 'g':
  571.     case 'G':
  572.         /* a precision of 0 is treated as a precision of 1. */
  573.         if (!prec)
  574.             ++prec;
  575.         /*
  576.          * ``The style used depends on the value converted; style e
  577.          * will be used only if the exponent resulting from the
  578.          * conversion is less than -4 or greater than the precision.''
  579.          *    -- ANSI X3J11
  580.          */
  581.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  582.             /*
  583.              * g/G format counts "significant digits, not digits of
  584.              * precision; for the e/E format, this just causes an
  585.              * off-by-one problem, i.e. g/G considers the digit
  586.              * before the decimal point significant and e/E doesn't
  587.              * count it as precision.
  588.              */
  589.             --prec;
  590.             fmtch -= 2;        /* G->E, g->e */
  591.             gformat = 1;
  592.             goto eformat;
  593.         }
  594.         /*
  595.          * reverse integer into beginning of buffer,
  596.          * note, decrement precision
  597.          */
  598.         if (expcnt)
  599.             for (; ++p < endp; *t++ = *p, --prec);
  600.         else
  601.             *t++ = '0';
  602.         /*
  603.          * if precision required or alternate flag set, add in a
  604.          * decimal point.  If no digits yet, add in leading 0.
  605.          */
  606.         if (prec || flags&ALT) {
  607.             dotrim = 1;
  608.             *t++ = decimal;
  609.         }
  610.         else
  611.             dotrim = 0;
  612.         /* if requires more precision and some fraction left */
  613.         while (prec && fract) {
  614.             fract = modf(fract * 10, &tmp);
  615.             *t++ = tochar((int)tmp);
  616.             prec--;
  617.         }
  618.         if (fract)
  619.             startp = round(fract, (int *)NULL, startp, t - 1,
  620.                     (char)0, signp);
  621.         /* alternate format, adds 0's for precision, else trim 0's */
  622.         if (flags&ALT)
  623.             for (; prec--; *t++ = '0');
  624.         else if (dotrim) {
  625.             while (t > startp && *--t == '0');
  626.             if (*t != decimal)
  627.                 ++t;
  628.         }
  629.     }
  630.     return(t - startp);
  631. }
  632.  
  633. static char *
  634. round(fract, exp, start, end, ch, signp)
  635.     double fract;
  636.     int *exp;
  637.     register char *start, *end;
  638.     char ch, *signp;
  639. {
  640.     double tmp;
  641.     double modf();
  642.  
  643.     if (fract)
  644.         (void)modf(fract * 10, &tmp);
  645.     else
  646.         tmp = todigit(ch);
  647.     if (tmp > 4)
  648.         for (;; --end) {
  649.             if (*end == decimal)
  650.                 --end;
  651.             if (++*end <= '9')
  652.                 break;
  653.             *end = '0';
  654.             if (end == start) {
  655.                 if (exp) {    /* e/E; increment exponent */
  656.                     *end = '1';
  657.                     ++*exp;
  658.                 }
  659.                 else {        /* f; add extra digit */
  660.                     *--end = '1';
  661.                     --start;
  662.                 }
  663.                 break;
  664.             }
  665.         }
  666.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  667.     else if (*signp == '-')
  668.         for (;; --end) {
  669.             if (*end == decimal)
  670.                 --end;
  671.             if (*end != '0')
  672.                 break;
  673.             if (end == start)
  674.                 *signp = 0;
  675.         }
  676.     return(start);
  677. }
  678.  
  679. static char *
  680. exponent(p, exp, fmtch)
  681.     register char *p;
  682.     register int exp;
  683.     u_char fmtch;
  684. {
  685.     register char *t;
  686.     char expbuf[MAXEXP];
  687.  
  688.     *p++ = fmtch;
  689.     if (exp < 0) {
  690.         exp = -exp;
  691.         *p++ = '-';
  692.     }
  693.     else
  694.         *p++ = '+';
  695.     t = expbuf + MAXEXP;
  696.     if (exp > 9) {
  697.         do {
  698.             *--t = tochar(exp % 10);
  699.         } while ((exp /= 10) > 9);
  700.         *--t = tochar(exp);
  701.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  702.     }
  703.     else {
  704.         *p++ = '0';
  705.         *p++ = tochar(exp);
  706.     }
  707.     return(p);
  708. }
  709.  
  710. #ifdef hp300
  711. isspecial(d, bufp, signp)
  712.     double d;
  713.     char *bufp, *signp;
  714. {
  715.     register struct IEEEdp {
  716.         unsigned sign:1;
  717.         unsigned exp:11;
  718.         unsigned manh:20;
  719.         unsigned manl:32;
  720.     } *ip = (struct IEEEdp *)&d;
  721.  
  722.     if (ip->exp != 0x7ff)
  723.         return(0);
  724.     if (ip->manh || ip->manl)
  725.         (void)strcpy(bufp, "NaN");
  726.     else
  727.         (void)strcpy(bufp, "Inf");
  728.     return(3);
  729. }
  730. #endif
  731.  
  732. #ifdef __GO32__
  733. static int isspecial(d, bufp)
  734.     double d;
  735.     char *bufp;
  736. {
  737.         register struct IEEEdp {
  738.             unsigned manl:32;
  739.             unsigned manh:20;
  740.             unsigned exp:11;
  741.             unsigned sign:1;
  742.     } *ip = (struct IEEEdp *)&d;
  743.  
  744.     if (ip->exp != 0x7ff)
  745.         return(0);
  746.     if (ip->manh || ip->manl)
  747.         {
  748.         strcpy(bufp, "NaN");
  749.             nan = 1; /* kludge: we don't need the sign,  it's not nice
  750.                     but it should work */
  751.         }
  752.     else
  753.         (void)strcpy(bufp, "Inf");
  754.         return(3);
  755. }
  756. #endif
  757.  
  758.